/**
 * Contain the Connection class
 *
 * @filename Connection.js
 * @$LastChangedDate$
 * @author Fabio Serra <faser@faser.net>
 * @copyright Fabio Serra (The Initial Developer of the Original Code)
 * @license Mozilla Public License Version 1.1
 *
*/

/**
 * Construct a new Connection object
 * @class Used to send GET or POST request to a server. The object provide a timeout and
 * return a connectionID that can be used to track multiple request made at the same time
 * @constructor
 * @param {string} targetUrl The URL to make a connection
 * @param {bool} permission Ask permission in case of MAB is not running as an extension
 * @throws XMLHttpRequest exception when unable to create an XMLHttpRequest object
 * @return A new Connection
 *
*/

// lexhung : some minor changes
function Connection(targetUrl) {
	/**
	 * The target URL
	 * @type string
	*/
	this.url = targetUrl;

	/**
	 * Need permission
     * @type bool
	*/
	this.blPermission = false; //(CONFIG.DRUPMAN_RUN == "local");
	// if(permission) { this.blPermission = true;}

	/**
	 * How long I have to wait for an answer before aborting. Default 1 minute
     * @type int
	*/
	this.timeout = 60000;// CONFIG.REQUEST_TIMEOUT;

	/**
	 * The interval id returned by the setInterval
     * @private
     * @type int
	*/
	this.intervalID = null;

	/**
	 * Connection ID to use with the callback function.
     * The caller have to know from which obj receive the result.
     * @private
     * @type int
	*/
	this.connectionID = Math.round(Math.random()*(10000000-1))+1;

	/**
	 * The server answer has been loaded?
     * @const
     * @type int
	*/
	this.COMPLETED = 4;

	/**
	 * This object contain all fields that should be returned after a connection
     * @type object
	*/
	this.retParams = {};
		/** Unique identifier */
		this.retParams.connectionID = this.connectionID;
		/**
		 * Returned status code. 0 means everything is OK
         * @type int
		*/
		this.retParams.status = 0;
		/**
		 * Associated text message
         * @type string
		*/
		this.retParams.message = "";
		/**
		 * Full response content as requested (XML or TXT)
    	*/
		this.retParams.content = "";
		/**
		 * The URL that generated the response
		*/
		this.retParams.requestedURL = "";


	//Create XMLHttpRequest object
	try {
		/**
		 * The XMLHttpRequest object
         * @type XMLHttpRequest
		*/
		this.req = new XMLHttpRequest();
	}catch(e){
		throw("Creating XMLHttpRequest:" + e);
	}
}

/**
 * Send a request to the target url
 * @param {string} string The query string
 * @param {string} method The HTTP request method (GET | POST)
 * @param {string} responseType The requested response type (txt | xml)
 * @return void
 * @throw netscape.security
 * @throw XMLHttpRequest open or send exceptions
*/
Connection.prototype.send = function(params, method, responseType) {
	//Request permission for remote application
	if(this.blPermission) {
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
		}catch (e){
			throw(e);
		}
	}

	//encode string
	if((typeof params) == 'string')
		params = encodeURI(params);

	var me = this;
	var lambda = function myScopeFunction(){
		me.getResponse(responseType);
	}

	//Abort current connection
	var timedOut = function() {
		me.abortConnection(10);
	}

	if(responseType == "xml") {this.req.overrideMimeType("text/xml");}

	switch(method) {
		case "GET":
			var qString = this.url + '?' + params;
			try {
				//Check for timeout
				this.intervalID =  setInterval(timedOut,this.timeout);
				this.req.open("GET",qString,true);
				//Save the request url
				this.retParams.requestedURL = qString;
				this.req.send(null);
			}catch(e){
				throw(e);
			}

			break;
		case "POST":
			try {
				//Check for timeout
				this.intervalID =  setInterval(timedOut,this.timeout);
				this.req.open("POST",this.url,true);
				this.retParams.requestedURL = this.url;
				this.req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
				this.req.send(params);
			}catch(e){
				throw(e);
			}
			break;
		default:
			throw("Connection Exception: method not supported");
	}
	this.req.onload = lambda;
}

/**
 * Handle the server response and send the result to the defined callback function
 * @param {string} responseType The requested response type (txt | xml)
 * @return void
*/

Connection.prototype.getResponse = function(responseType) {
	if(this.req.readyState == this.COMPLETED) {
		//Clear Inteval for timeout checking
		clearInterval(this.intervalID);
		//Request permission for remote application
		if(this.req.status !=200) {
			this.connectionException(20);
			this.errorCallback(this.retParams);
		} else {
			
			// Require UniversalBrowserRead permission to read returned XMLDocument object.
			if(this.blPermission) {
				try {
					netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
				}catch (e){
					throw(e);
				}
			}
			
			if(responseType == "txt") {
				this.retParams.content = this.req.responseText;
				this.retParams.methodName = this.xmlrpcMethodName;
				this.callBack(this.retParams);
			}else{
				// var responseXML = new DOMParser().parseFromString(this.req.responseText, 'text/xml');
				this.retParams.contentText = this.req.responseText;
				this.retParams.content = this.req.responseXML;
				this.retParams.methodName = this.xmlrpcMethodName;
				this.callBack(this.retParams);
			}
		}
	}
}

/**
 * To pass the reference to the function to be called when the data is available.
 * @param {string} fRef function name
 * @return void
*/
Connection.prototype.setCallback= function (fRef) {
	this.callBack=fRef;
}

/**
 * To pass the reference to the function in case of errors
 * @param {string} fRef function name
 * @return void
*/
Connection.prototype.setErrorCallback= function (fRef) {
	this.errorCallback=fRef;
}

/**
 * Abort in progress connection
 * @param {int} errorCode provide a properly error code
 * @return void
 * @throw exception
*/
Connection.prototype.abortConnection = function(errorCode) {
	try {
		this.req.abort();
		clearInterval(this.intervalID);
		this.connectionException(errorCode);
		this.errorCallback(this.retParams);
	}catch(e){
		throw(e);
	}
}

/**
 * Set the status code and a message in case of error
 * @param {int} errorCode An error code
 * @return void
*/
Connection.prototype.connectionException = function (errorCode) {
	switch(errorCode) {
		//TimeOut
		case 10:
			this.retParams.status = errorCode;
			this.retParams.message = "Connection has timed out";
			break;
		case 20:
			this.retParams.status = errorCode;
			this.retParams.message = "The server respond with a bad status code: " + this.req.status;
			//check if the response have some more info in html format
			if(this.req.responseText) {
				//TODO - LIMIT TEXT
				//this.retParams.message += "\n" + stripHTML(this.req.responseText);
			}
			break;
		case 30:
			this.retParams.status = errorCode;
			this.retParams.message = "Connection cancelled by user";
			break;
		case 40:
			this.retParams.status = errorCode;
			this.retParams.message = "General connection failure";
			break;
	}
}
